<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="ozZIz" id="ozZIz"><span data-lake-id="u63be82e4" id="u63be82e4">典型回答</span></h1>
  <p data-lake-id="uc499617e" id="uc499617e"><br></p>
  <p data-lake-id="u101d65fd" id="u101d65fd"><br></p>
  <p data-lake-id="u87fc01bc" id="u87fc01bc"><span data-lake-id="u16f2cbb9" id="u16f2cbb9">首先看看B+树有哪些特点：</span></p>
  <p data-lake-id="u3b81527b" id="u3b81527b"><span data-lake-id="ubcd16bb0" id="ubcd16bb0">​</span><br></p>
  <ol list="u046c64ae">
   <li fid="u3b23803f" data-lake-id="u725d92a3" id="u725d92a3"><span data-lake-id="ubd4aabd6" id="ubd4aabd6">B+树是一棵</span><strong><span data-lake-id="uc731bd9d" id="uc731bd9d">平衡树</span></strong><span data-lake-id="u97c525a5" id="u97c525a5">，每个叶子节点到根节点的路径长度相同，查找效率较高；</span></li>
   <li fid="u3b23803f" data-lake-id="u872f2012" id="u872f2012"><span data-lake-id="u99a1b6d3" id="u99a1b6d3">B+树的</span><strong><span data-lake-id="uadb37f87" id="uadb37f87">所有关键字都在叶子节点上</span></strong><span data-lake-id="u6cf29258" id="u6cf29258">，因此范围查询时只需要遍历一遍叶子节点即可；</span></li>
   <li fid="u3b23803f" data-lake-id="ua20af571" id="ua20af571"><span data-lake-id="u2c017ea2" id="u2c017ea2">B+树的叶子节点都按照关键字大小</span><strong><span data-lake-id="u3ff3e80b" id="u3ff3e80b">顺序存放</span></strong><span data-lake-id="u603be3e7" id="u603be3e7">，因此可以快速地支持按照关键字大小进行排序；</span></li>
   <li fid="u3b23803f" data-lake-id="ua5478fbc" id="ua5478fbc"><span data-lake-id="u2c0d8380" id="u2c0d8380">B+树的</span><strong><span data-lake-id="u23df7a2e" id="u23df7a2e">非叶子节点不存储实际数据</span></strong><span data-lake-id="u1d29b42f" id="u1d29b42f">，因此可以存储更多的索引数据；</span></li>
   <li fid="u3b23803f" data-lake-id="ufba0d194" id="ufba0d194"><span data-lake-id="u56e28e8c" id="u56e28e8c">B+树的非叶子节点使用指针连接子节点，因此可以快速地支持范围查询和倒序查询。</span></li>
   <li fid="u3b23803f" data-lake-id="uf5309ceb" id="uf5309ceb"><strong><span data-lake-id="u358b6cca" id="u358b6cca">B+树的叶子节点之间通过双向链表链接</span></strong><span data-lake-id="ue75ba47b" id="ue75ba47b">，方便进行范围查询。</span></li>
  </ol>
  <p data-lake-id="u3e2b0d86" id="u3e2b0d86"><span data-lake-id="u13482af5" id="u13482af5">​</span><br></p>
  <p data-lake-id="u862e4dbe" id="u862e4dbe"><span data-lake-id="u64c3568c" id="u64c3568c">​</span><br></p>
  <p data-lake-id="uc608588c" id="uc608588c"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1698478818412-6f6f8b64-5aef-4975-b5fa-a85211492288.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_42%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u1ad3c32c" id="u1ad3c32c"><br></p>
  <p data-lake-id="u0f5f4a23" id="u0f5f4a23"><br></p>
  <p data-lake-id="ub646f534" id="ub646f534"><span data-lake-id="u5ebbf3b9" id="u5ebbf3b9">那么，使用B+树实现索引，就有以下几个优点：</span></p>
  <p data-lake-id="u7f5f4cee" id="u7f5f4cee"><span data-lake-id="u932d1763" id="u932d1763">​</span><br></p>
  <ol list="ub026379e">
   <li fid="u6e0c1afb" data-lake-id="u6f4af3c0" id="u6f4af3c0"><strong><span data-lake-id="u281a8a05" id="u281a8a05">支持范围查询</span></strong><span data-lake-id="ub519e6d3" id="ub519e6d3">，B+树在进行范围查找时，只需要从根节点一直遍历到叶子节点，因为数据都存储在叶子节点上，而且叶子节点之间有指针连接，可以很方便地进行范围查找。</span></li>
   <li fid="u6e0c1afb" data-lake-id="u18a7752c" id="u18a7752c"><strong><span data-lake-id="udd7f588f" id="udd7f588f">支持排序</span></strong><span data-lake-id="u04e45223" id="u04e45223">，B+树的叶子节点按照关键字顺序存储，可以快速支持排序操作，提高排序效率；</span></li>
   <li fid="u6e0c1afb" data-lake-id="u85d84e2a" id="u85d84e2a"><strong><span data-lake-id="u619b5595" id="u619b5595">存储更多的索引数据</span></strong><span data-lake-id="u688dbb88" id="u688dbb88">，因为它的非叶子节点只存储索引关键字，不存储实际数据，因此可以存储更多的索引数据；</span></li>
   <li fid="u6e0c1afb" data-lake-id="uc394b9d5" id="uc394b9d5"><strong><span data-lake-id="u167eaab1" id="u167eaab1">在节点分裂和合并时，IO操作少</span></strong><span data-lake-id="u4b8d8c99" id="u4b8d8c99">。B+树的叶子节点的大小是固定的，而且节点的大小一般都会设置为一页的大小，这就使得节点分裂和合并时，IO操作很少，只需读取和写入一页。</span></li>
   <li fid="u6e0c1afb" data-lake-id="u87fcc993" id="u87fcc993"><strong><span data-lake-id="u0d1c9301" id="u0d1c9301">有利于磁盘预读</span></strong><span data-lake-id="u0f41cf91" id="u0f41cf91">。由于B+树的节点大小是固定的，因此可以很好地利用磁盘预读特性，一次性读取多个节点到内存中，这样可以减少IO操作次数，提高查询效率。</span></li>
   <li fid="u6e0c1afb" data-lake-id="uc3c2edd4" id="uc3c2edd4"><strong><span data-lake-id="uf895e211" id="uf895e211">有利于缓存</span></strong><span data-lake-id="u29565dc9" id="u29565dc9">。B+树的非叶子节点只存储指向子节点的指针，而不存储数据，这样可以使得缓存能够容纳更多的索引数据，从而提高缓存的命中率，加快查询速度。</span></li>
  </ol>
  <p data-lake-id="u2b3b1e99" id="u2b3b1e99"><br></p>
  <h1 data-lake-id="Y6YP9" id="Y6YP9"><span data-lake-id="ub40e59a9" id="ub40e59a9">扩展知识</span></h1>
  <p data-lake-id="ue1944a9d" id="ue1944a9d"><br></p>
  <h2 data-lake-id="PpjPE" id="PpjPE"><span data-lake-id="u29845c9b" id="u29845c9b">为什么不用红黑树或者B树？</span></h2>
  <p data-lake-id="ufdcf8f15" id="ufdcf8f15"><br></p>
  <p data-lake-id="u100d9705" id="u100d9705"><span data-lake-id="u701e7b16" id="u701e7b16">因为B+树的特点是只有叶子节点存储数据，而非叶子节点不存储数据，并且节点大小固定，还有就是叶子结点之间通过双向链表链接的，所以，使用B+树实现索引有很多好处，比如我们前面提到的支持范围查询、有利于磁盘预读、有利于优化排序等等。而这些是红黑树和B树做不到的。</span></p>
  <p data-lake-id="uc4b07669" id="uc4b07669"><br></p>
  <h2 data-lake-id="cbLXC" id="cbLXC"><span data-lake-id="ub6df4f36" id="ub6df4f36" class="lake-fontsize-12" style="color: rgb(52, 53, 65)">B+树索引和Hash索引有什么区别？</span></h2>
  <p data-lake-id="uecb3b193" id="uecb3b193"><br></p>
  <p data-lake-id="u69ce932c" id="u69ce932c"><span data-lake-id="uc5d70e02" id="uc5d70e02">B+ 树索引和哈希索引是常见的数据库索引结构，它们有以下几个主要区别：</span></p>
  <p data-lake-id="u5a4ef122" id="u5a4ef122"><span data-lake-id="u02c7e54a" id="u02c7e54a">​</span><br></p>
  <p data-lake-id="u72da2d42" id="u72da2d42"><span data-lake-id="uf98c9d52" id="uf98c9d52">B+ 树索引将索引列的值按照大小排序后存储，因此</span><strong><span data-lake-id="u6765b793" id="u6765b793">B+ 树索引适合于范围查找和排序操作</span></strong><span data-lake-id="u20ae10e2" id="u20ae10e2">；而哈希索引是将索引列的值通过哈希函数计算后得到一个桶的编号，然后将桶内的记录保存在一个链表或者树结构中。因此，</span><strong><span data-lake-id="u2c7673c8" id="u2c7673c8">哈希索引适合于等值查询，但不适合范围查询和排序操作。</span></strong></p>
  <p data-lake-id="u53dfd899" id="u53dfd899"><br></p>
  <p data-lake-id="ua6c1f859" id="ua6c1f859"><span data-lake-id="u89d28763" id="u89d28763">B+ 树索引在插入和删除数据时需要调整索引结构，这个过程可能会涉及到页分裂和页合并等操作，</span><strong><span data-lake-id="u578976dc" id="u578976dc">因此B+ 树索引的维护成本比较高</span></strong><span data-lake-id="u7757c169" id="u7757c169">；而哈希索引在插入和删除数据时只需要计算哈希值并插入或删除链表中的记录，</span><strong><span data-lake-id="uc69dc64c" id="uc69dc64c">因此哈希索引的维护成本相对较低。</span></strong></p>
  <p data-lake-id="u1cc971ca" id="u1cc971ca"><span data-lake-id="ufaefaecf" id="ufaefaecf">​</span><br></p>
  <p data-lake-id="ucd16b9a2" id="ucd16b9a2"><strong><span data-lake-id="u9048b118" id="u9048b118">B+ 树索引在磁盘上是有序存储的</span></strong><span data-lake-id="u69298914" id="u69298914">，因此在进行区间查询时可以利用磁盘预读的优势提高查询效率；而</span><strong><span data-lake-id="uba38c3b0" id="uba38c3b0">哈希索引在磁盘上是无序存储的</span></strong><span data-lake-id="u6c17c7e4" id="u6c17c7e4">，因此在进行区间查询时可能会需要随机访问磁盘，导致查询效率降低。</span></p>
  <p data-lake-id="u5027bc3b" id="u5027bc3b"><span data-lake-id="u95a72ad6" id="u95a72ad6">​</span><br></p>
  <p data-lake-id="u16ed8880" id="u16ed8880"><span data-lake-id="u443b0cfd" id="u443b0cfd">B+ 树索引在节点中存储多个键值对，因此可以充分利用磁盘块的空间，提高空间利用率；而哈希索引由于需要存储哈希值和指针，因此空间利用率相对较低。</span></p>
 </body>
</html>